#include "Octree.h"
#include "FireEmitter.h"
#include "Renderer.h"
#include "DXMgr.h"
#include "Drawable.h"
#include "Text.h"
#include "SoundEmitter.h"
#include "SoundMgr.h"

Octree::Octree()
: m_pRootNode(NULL)
, m_pDebugText(NULL)
, m_wireframeRendering(false)
, m_numCollisionChecks(0)
{

}
Octree::Octree(int a_max)
: m_pRootNode(NULL)
, m_pDebugText(NULL)
, m_wireframeRendering(false)
, m_numCollisionChecks(0)
{
	//Set the max number of objects per node
	m_maxObjects = a_max;
}
Octree::~Octree()
{
	//Clean up the root node
	if(m_pRootNode)
	{
		delete m_pRootNode;
		m_pRootNode = NULL;
	}
	//Clean up the debug text
	if(m_pDebugText)
	{
		delete m_pDebugText;
		m_pDebugText = NULL;
	}
}

void Octree::CreateOctree(AABB a_aabb)
{
	//Store the renderer to save too many calls to get instance during recursion
	m_pRenderer = &Renderer::GetInstance();

	//Create the first node based on input data
	m_pRootNode = new Node(m_maxObjects, &a_aabb, &m_pRenderer->GetOctreeList());
	
	//Set the debug data
	m_numNodesWithObjects = 0;
	//Depth of one cause of the root node above
	m_depth = 1;

	Traverse(m_pRootNode);
	
	//Setup output debug text
	m_pDebugText = new Text();
	m_pDebugText->CreateObject(DXMgr::GetInstance().GetDevice(), NULL, 14, NULL, 10, 50, D3DCOLOR_XRGB(255,255,255));
	m_pRenderer->AddText(m_pDebugText);
}
void Octree::TraverseAndRender(Node* a_pNode)
{
	//Check if the node is inside the first camera (this is for debugbing only, normally would call GetActiveCamera())
	if(m_pRenderer->GetActiveCamera()->GetFrustum()->FrustumCollision(a_pNode))
	{
		//If its a leaf node
		if(!a_pNode->HasChildren())
		{
			//Dont call render if there aren't any objects
			if(!a_pNode->GetObjectList().empty())
			{
				//Only want objects to be drawn once, so add them to the list of drawables if they aren't already there
				for(Renderer::DrawableObjectList::iterator iter = a_pNode->GetObjectList().begin(); iter != a_pNode->GetObjectList().end(); iter++)
				{
					Drawable* pElem = *iter;
					m_pRenderer->AddOctreeObjectToRender(pElem);
				}
			}
		}
		else
		{
			//If its a branch node, traverse through all of its child nodes
			for(UINT i=0; i<a_pNode->GetNodes().size(); ++i)
			{
				TraverseAndRender(a_pNode->GetChild(i));
			}
		}
	}
}
void Octree::FillRenderList()
{
	TraverseAndRender(m_pRootNode);

	//Draw debug text
	char* pBuffer = new char[256];

	sprintf_s(pBuffer, 256, "Max Objects: %i \nNodes Containing Objects: %i\nObjects in the Scene: %i\nObjects Not Being Drawn: %i\nTree Depth: %i \n", m_maxObjects, m_numNodesWithObjects, m_pRenderer->GetOctreeList().size(), m_pRenderer->GetOctreeList().size() - m_pRenderer->GetOctreeObjectsToRender()->size() , m_depth);
	m_pDebugText->SetText(pBuffer);	
}

void Octree::Traverse(Node* a_pNode)
{
	//Check if theres too many objects
	if(a_pNode->GetObjectList().size() > (UINT)m_maxObjects)
	{
		//Sweet optimization - don't allow any more divisions past a certain point, stops it from creating
		//too many nodes when there are objects really close together
		if((a_pNode->GetAABB().GetMax().x - a_pNode->GetAABB().GetMin().x) > 5.0f)
		{
			//Convert the node into a branch node
			a_pNode->ConvertToBranch();
			//Another level has been added to the tree, add it to the counter
			++m_depth;
		}
	}
	//Simple debug info
	if(a_pNode->GetObjectList().size() > 0)
	{
		++m_numNodesWithObjects;
	}

	if(a_pNode->HasChildren())
	{
		//Traverse through all child nodes
		for(UINT i=0; i<a_pNode->GetNodes().size(); ++i)
		{
			Traverse(a_pNode->GetChild(i));
		}
	}
}